home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Modules / BackSpaceModules / Source / FireflyView / FireflyView.m < prev    next >
Text File  |  1993-07-04  |  13KB  |  417 lines

  1. /*
  2.     file:
  3.         FireflyView.m
  4.     
  5.     history:
  6.         1993-06-06, andrew abernathy
  7.             • created
  8.         1993-07-04, andrew abernathy
  9.             • added configurability
  10. */
  11.  
  12.  
  13. #import <appkit/appkit.h>
  14. #import "FireflyView.h"
  15.  
  16.  
  17. #define DEFAULTS_OWNER    "BackSpace.Fireflies"            // this is the owner name to use for the defaults database
  18.  
  19.  
  20. // this macro returns a random integer between min & max
  21.  
  22. #define randomIn(min,max)    ((random () % (max - min)) + min)
  23.  
  24.  
  25. // convert an NXColor to an ASCII representation
  26.  
  27. static char *    ColorToASCII (NXColor color, char * buf)
  28.     {
  29.     float    red, green, blue;
  30.     
  31.     NXConvertColorToRGB (color, &red, &green, &blue);
  32.     sprintf (buf, "%f:%f:%f", red, green, blue);
  33.     return buf;
  34.     }
  35.     
  36.  
  37. // convert an ASCII representation to an NXColor
  38.     
  39. static NXColor    ASCIIToColor (const char * buf)
  40.     {
  41.     float    red, green, blue;
  42.     
  43.     sscanf (buf, "%f:%f:%f", &red, &green, &blue);
  44.     return NXConvertRGBToColor (red, green, blue);
  45.     }
  46.  
  47.  
  48. // register our defaults
  49.  
  50. static void    RegisterDefaults (void)
  51.     {
  52.     static    NXDefaultsVector    FireflyDefaults  =
  53.             {
  54.                 { "FireflyColor", "1.0:1.0:1.0" },    // fireflies default to white
  55.                 { "FireflyCount", "60" },        // 60 fireflies initially
  56.                 { "BackgroundColor", "0:0:0" },        // background starts at black
  57.                 { "BoringModule", "YES" },        // yeah, we're a boring module
  58.                 { NULL, NULL }
  59.             };
  60.             
  61.     NXRegisterDefaults (DEFAULTS_OWNER, FireflyDefaults);        // register the defaults
  62.     }
  63.         
  64.  
  65. @implementation    FireflyView:View
  66.  
  67.  
  68. /*
  69. Here we do class initialization.  All we do right now is set up our defaults.
  70. */
  71.  
  72. + initialize
  73.     {
  74.     RegisterDefaults ();
  75.     return self;
  76.     }
  77.     
  78.  
  79. /*
  80. Here we're notified that our inspector has been installed.  We use this for most of the initialization as we don't know of a better place; because of the way BackSpace does things, we're sure this will always get called before the screen saver module actually kicks in.  Besides, we can't make our inspector reflect our configuration data before the inspector is loaded.  If we already have some fireflies, everything must already be set up, so we don't worry about it.
  81.  
  82. Our first group of fireflies will just be wasted - never drawn.  However, this is better than checking to make sure we don't release or draw non-existant fireflies every time we get a oneStep message.
  83. */
  84.  
  85. - inspectorInstalled
  86.     {
  87.     if (!fireflies)            // no fireflies, better do setup
  88.         {
  89.         fireflyColor = ASCIIToColor (NXGetDefaultValue (DEFAULTS_OWNER, "FireflyColor"));
  90.         [fireflyColorWell setColor:fireflyColor];    // update the firefly color well on the inspector
  91.     
  92.         fireflyCount = atoi (NXGetDefaultValue (DEFAULTS_OWNER, "FireflyCount"));
  93.         [fireflyCountField setIntValue:fireflyCount];    // update the count field on the inspector
  94.         fireflyCountChanged = FALSE;            // we don't have to worry about this since we set the count manually
  95.     
  96.         backgroundColor = ASCIIToColor (NXGetDefaultValue (DEFAULTS_OWNER, "BackgroundColor"));
  97.         [backgroundColorWell setColor:backgroundColor];    // update the background color well on the inspector
  98.         backgroundColorChanged = TRUE;            // so that we read the color and clear the frame in "oneStep"
  99.     
  100.         isBoring = strcmp (NXGetDefaultValue (DEFAULTS_OWNER, "BoringModule"), "YES") == 0;
  101.         [isBoringSwitch setState:(isBoring ? 1 : 0)];    // update the boring module switch on the inspector
  102.     
  103.         fireflies = [self generateFireflies:fireflyCount];    // create some fireflies
  104.     
  105.         }
  106.     
  107.     [fireflyCountField selectText:self];            // select the firefly count so that we can quickly type to change it
  108.     return self;
  109.     }
  110.  
  111.  
  112. /*
  113. Here we make a single "move":  create new fireflies, draw them, then erase the old fireflies.  Erasing in the end provides the potential for erasing new fireflies, if they happen to fall in the same position as an old firefly, but this is minor, and it avoids the flicker caused by: bunch of fireflies, black, bunch of fireflies, black, etc.  Erasing old fireflies individually is much slower than just blacking everything out, but if we blacked everything out, we would get flicker.  Best would be to draw a single firefly, then erase the equivalent "old" firefly, but this is much slower due to the constant color changes.  Maybe I should be doing this off screen, but I don't know that much yet.
  114. */
  115.  
  116. - oneStep
  117.     {
  118.     int        firefly;                // firefly counter
  119.     NXPoint *    oldFireflies;                // the old fireflies
  120.     int        oldFireflyCount;            // number of old fireflies
  121.     
  122.     if (backgroundColorChanged)                // background color changed; redraw the background
  123.         {
  124.         backgroundColor = [backgroundColorWell color];    // get new color
  125.         NXSetColor (backgroundColor);            // set the color to redraw the background in
  126.         PSrectfill (0, 0, NX_WIDTH (&frame), NX_HEIGHT (&frame));
  127.         }
  128.         
  129.     oldFireflies = fireflies;                // save the old fireflies
  130.     oldFireflyCount = fireflyCount;                // save the old fireflies count
  131.     
  132.     if (fireflyCountChanged)                // new number of fireflies
  133.         {
  134.         fireflyCount = [fireflyCountField intValue];    // get new count
  135.         fireflyCountChanged = FALSE;            // reset firefly count changed flag
  136.         }
  137.     fireflies = [self generateFireflies:fireflyCount];    // make new fireflies
  138.     NXSetColor (fireflyColor);                // set the color to draw the fireflies in
  139.     for (firefly = 0; firefly < fireflyCount; firefly++)    // draw the fireflies
  140.         {
  141.         PSrectfill (fireflies[firefly].x, fireflies[firefly].y, 1.0, 1.0);
  142.         }
  143.     
  144.     if (!backgroundColorChanged)                // background didn't change, so we need to "black out" old fireflies
  145.         {
  146.         NXSetColor (backgroundColor);                // set the color to erase the old fireflies with
  147.         for (firefly = 0; firefly < oldFireflyCount; firefly++)    // erase the old fireflies
  148.             {
  149.             PSrectfill (oldFireflies[firefly].x, oldFireflies[firefly].y, 1.0, 1.0);
  150.             }
  151.         }
  152.     else                            // background DID change...
  153.         {
  154.         backgroundColorChanged = FALSE;            // reset background changed flag
  155.         }
  156.     
  157.     if (oldFireflies)                    // got old fireflies?
  158.         {
  159.         free (oldFireflies);                // delete the old fireflies
  160.         }
  161.         
  162.     return self;
  163.     }
  164.  
  165.  
  166. /*
  167. We're going to get a oneStep message in a second; don't bother to draw everything, but say that we have a new background color to ensure that we clear our drawing area.
  168. */
  169.  
  170. - drawSelf:(const NXRect *)rects :(int)rectCount
  171.     {
  172.     backgroundColorChanged = TRUE;
  173.     return self;
  174.     }
  175.  
  176.  
  177. /*
  178. Most of our initialization is actually done in the "inspectorInstalled" method - we assume that our inspector is always pulled up once (manually or by BackSpace) before we begin executing.
  179. */
  180.  
  181. - initFrame:(const NXRect *)frameRect
  182.     {
  183.     
  184.     [super initFrame:frameRect];
  185.     [self allocateGState];        // For faster lock/unlockFocus
  186.     [self setClipping:NO];        // even faster...
  187.     srandom (time (0));        // seed random number generator
  188.     
  189.     return self;
  190.     }
  191.  
  192.  
  193. /*
  194. Find our inspector panel and return it.
  195. */
  196.  
  197. - inspector:sender
  198.     {
  199.     char buf[MAXPATHLEN];
  200.  
  201.     if (!sharedInspectorPanel)    // inspector not loaded yet?  do so now.
  202.         {
  203.         sprintf (&buf[0], "%s/%s", [(BSThinker ()) moduleDirectory:"Firefly"], "FireflyView.nib");
  204.         [NXApp loadNibFile:buf owner:self withNames:NO];
  205.         }
  206.  
  207.     return sharedInspectorPanel;
  208.     }
  209.  
  210.  
  211. /*
  212. Create some fireflies, position them, and return them for life (albeit brief) in the great outdoors.
  213. */
  214.  
  215. - (NXPoint *)generateFireflies:(int)numFireflies
  216.     {
  217.     int        firefly;
  218.     NXPoint *    newFireflies;
  219.     
  220.     newFireflies = (NXPoint *) malloc (sizeof (NXPoint) * numFireflies);
  221.     for (firefly = 0; firefly < fireflyCount; firefly++)
  222.         {
  223.         newFireflies[firefly].x = (NXCoord) randomIn (0, (int) NX_WIDTH (&frame));
  224.         newFireflies[firefly].y = (NXCoord) randomIn (0, (int) NX_HEIGHT (&frame));
  225.         }
  226.     
  227.     return newFireflies;
  228.     }
  229.  
  230.  
  231. /*
  232. If we say we're boring, BackSpace won't call on us if it's in the "All" mode.
  233. */
  234.  
  235. - (BOOL)isBoringScreenSaver
  236.     {
  237.     return isBoring;
  238.     }
  239.     
  240.     
  241. /*
  242. Movement in the background color well - let's see if the color actually changed.  If so, we note that it changed and write the new color to the defaults database.  We don't actually set the new color; that's done in the "oneStep" method, or colors get confused.
  243. */
  244.  
  245. - setBackgroundColor:sender
  246.     {
  247.     char    buf[256];
  248.     NXColor    tempColor;
  249.     
  250.     tempColor = [backgroundColorWell color];
  251.     if (!NXEqualColor (tempColor, backgroundColor))
  252.         {
  253.         backgroundColorChanged = TRUE;
  254.         NXWriteDefault (DEFAULTS_OWNER, "BackgroundColor", ColorToASCII (tempColor, &buf[0]));
  255.         }
  256.         
  257.     return self;
  258.     }
  259.     
  260.     
  261. /*
  262. Movement in the firefly color well - lets see if the color actually changed.  If so, we set the new color and write the new color to the defaults database.  We go ahead and set the new firefly color here as nothing gets confused when we do.
  263. */
  264.  
  265. - setFireflyColor:sender
  266.     {
  267.     char    buf[256];
  268.     NXColor    tempColor;
  269.     
  270.     tempColor = [sender color];
  271.     if (!NXEqualColor (tempColor, fireflyColor))
  272.         {
  273.         fireflyColor = tempColor;
  274.         NXWriteDefault (DEFAULTS_OWNER, "FireflyColor", ColorToASCII (fireflyColor, &buf[0]));
  275.         }
  276.     
  277.     return self;
  278.     }
  279.     
  280.     
  281. /*
  282. Movement in the firefly count field.  If the new count is negative, reset the field, as negative numbers are invalid.  Otherwise, if the new count is actually different from the old count, we note that fact and write the new value to the defaults database.  We don't actually set the new count here or we risk not erasing old fireflies or erasing fireflies that didn't exist, tromping through memory we didn't allocate and happily grabbing non-existant (and often very strange) new fireflies.  Kind of a bad thing, overall.
  283. */
  284.  
  285. - setFireflyCount:sender
  286.     {
  287.     char    buf[256];
  288.     int    tempCount;
  289.     
  290.     tempCount = [sender intValue];
  291.     if (tempCount < 0)    // don't allow negative number of fireflies
  292.         {
  293.         [sender setIntValue:fireflyCount];
  294.         }
  295.     else if (fireflyCount != tempCount)    // the count really did change?
  296.         {
  297.         // we don't set the count here - that'll be done in "oneStep"
  298.         fireflyCountChanged = TRUE;
  299.         sprintf (&buf[0], "%d", tempCount);
  300.         NXWriteDefault (DEFAULTS_OWNER, "FireflyCount", &buf[0]);
  301.         [fireflyCountField setIntValue:tempCount];    // update the count field in case they entered a number larger than MAXINT
  302.         }
  303.     
  304.     [fireflyCountField selectText:self];
  305.         
  306.     return self;
  307.     }
  308.     
  309.     
  310. /*
  311. Movement with the boring module switch; check the switch and set the corresponding flag and write the value to the defaults database.
  312. */
  313.  
  314. - setIsBoring:sender
  315.     {
  316.     switch ([sender state])
  317.         {
  318.         case 0:        // not set
  319.             isBoring = FALSE;
  320.             NXWriteDefault (DEFAULTS_OWNER, "BoringModule", "NO");
  321.             break;
  322.         case 1:        // IS set
  323.             isBoring = TRUE;
  324.             NXWriteDefault (DEFAULTS_OWNER, "BoringModule", "YES");
  325.             break;
  326.         default:
  327.             // error!  should always be 0 or 1, so we ignore this case.  shouldn't ever occur, anyway.
  328.             break;
  329.         }
  330.     
  331.     return self;
  332.     }
  333.  
  334.  
  335. /*
  336. Open the readme file for the user's reading pleasure.
  337. */
  338.  
  339. - openReadme:sender
  340.     {
  341.     char    buf[MAXPATHLEN];
  342.     
  343.     sprintf (&buf[0], "open %s/%s", [(BSThinker ()) moduleDirectory:"Firefly"], "Info.rtf");
  344.     system (&buf[0]);
  345.     return self;
  346.     }
  347.     
  348. /*
  349. Reset the configuration settings to their defaults.  A side benefit of the way I did this is that it cleans out the defaults database of values for this module, so someone removing the module from their system can easily remove all of the associated defaults.  Here we remove all of the defaults, re-register the defaults, and re-read the defaults.  We have to re-register our defaults or the act of looking one up causes a crash.  (Guess how I learned about that...)
  350. */
  351.  
  352. - resetSettings:sender
  353.     {
  354.     const char *    tempStr;
  355.     
  356.     // remove defaults
  357.     NXRemoveDefault (DEFAULTS_OWNER, "FireflyColor");
  358.     NXRemoveDefault (DEFAULTS_OWNER, "FireflyCount");
  359.     NXRemoveDefault (DEFAULTS_OWNER, "BackgroundColor");
  360.     NXRemoveDefault (DEFAULTS_OWNER, "BoringModule");
  361.     
  362.     // re-register defaults
  363.     RegisterDefaults ();
  364.  
  365.     // re-read defaults and update inspector
  366.     tempStr = NXGetDefaultValue (DEFAULTS_OWNER, "FireflyColor");
  367.     if (tempStr)                    // got a valid string
  368.         {
  369.         fireflyColor = ASCIIToColor (tempStr);
  370.         [fireflyColorWell setColor:fireflyColor];
  371.         }
  372.     else
  373.         {
  374.         NXRunAlertPanel (0, "Could not determine firefly color", 0, 0, 0);
  375.         }
  376.     
  377.     tempStr = NXGetDefaultValue (DEFAULTS_OWNER, "FireflyCount");
  378.     if (tempStr)
  379.         {
  380.         [fireflyCountField setIntValue:atoi (tempStr)];
  381.         fireflyCountChanged = TRUE;            // make sure that we read this in "oneStep"
  382.         }
  383.     else
  384.         {
  385.         NXRunAlertPanel (0, "Could not determine number of fireflies", 0, 0, 0);
  386.         }
  387.  
  388.     tempStr = NXGetDefaultValue (DEFAULTS_OWNER, "BackgroundColor");
  389.     if (tempStr)
  390.         {
  391.         [backgroundColorWell setColor:ASCIIToColor (tempStr)];
  392.         backgroundColorChanged = TRUE;            // so that we read the color and clear the frame in "oneStep"
  393.         }
  394.     else
  395.         {
  396.         NXRunAlertPanel (0, "Could not determine background color", 0, 0, 0);
  397.         }
  398.  
  399.     tempStr = NXGetDefaultValue (DEFAULTS_OWNER, "BoringModule");
  400.     if (tempStr)
  401.         {
  402.         isBoring = strcmp (tempStr, "YES") == 0;
  403.         [isBoringSwitch setState:(isBoring ? 1 : 0)];
  404.         }
  405.     else
  406.         {
  407.         NXRunAlertPanel (0, "Could not determine whether or not module is boring", 0, 0, 0);
  408.         }
  409.  
  410.     [fireflyCountField selectText:self];        // select the firefly count so that we can quickly type to change it
  411.  
  412.     return self;
  413.     }
  414.     
  415.  
  416. @end
  417.